//SPDX-FileCopyrightText: Copyright 2025-2025 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package dao

import (
	"context"
	"encoding/json"
	"time"

	"github.com/redis/go-redis/v9"
)

const _CACHE_PREFIX_SESS = "sess:"
const _CACHE_PREFIX_ADMIN_SESS = "admsess:"
const CACHE_PREFIX_USER_ONLINE = "useronline:"

type SessionDbItem struct {
	SessionId   string `json:"sessionId"`
	UserId      string `json:"userId"`
	UserName    string `json:"userName"`
	DisplayName string `json:"displayName"`
	LogoUri     string `json:"logUri"`
}

type AdminSessionDbItem struct {
	AdminSessionId string `json:"adminSessionId"`
	UserName       string `json:"userName"`
	ToSignStr      string `json:"toSignStr"`
	AuthOk         bool   `json:"authOk"`
}

type _CacheDao struct {
	rdb     *redis.Client
	msgChan <-chan *redis.Message
}

func newCacheDao(rdb *redis.Client) (*_CacheDao, error) {
	err := rdb.ConfigSet(context.Background(), "notify-keyspace-events", "Ex").Err()
	if err != nil {
		return nil, err
	}
	msgChan := rdb.PSubscribe(context.Background(), "__key*__:*").Channel()
	return &_CacheDao{rdb: rdb, msgChan: msgChan}, nil
}

func (db *_CacheDao) GetMsgChan() <-chan *redis.Message {
	return db.msgChan
}

func (db *_CacheDao) SetSession(ctx context.Context, dbItem *SessionDbItem) error {
	data, err := json.Marshal(dbItem)
	if err != nil {
		return err
	}
	err = db.rdb.SetEx(ctx, _CACHE_PREFIX_SESS+dbItem.SessionId, data, 1*time.Minute).Err()
	if err != nil {
		return err
	}
	return db.rdb.SetEx(ctx, CACHE_PREFIX_USER_ONLINE+dbItem.UserId, "", 1*time.Minute).Err()
}

func (db *_CacheDao) GetSession(ctx context.Context, sessionId string) (*SessionDbItem, bool) {
	data, err := db.rdb.Get(ctx, _CACHE_PREFIX_SESS+sessionId).Result()
	if err != nil {
		return nil, false
	}
	retItem := &SessionDbItem{}
	err = json.Unmarshal([]byte(data), retItem)
	if err != nil {
		return nil, false
	}
	return retItem, true
}

func (db *_CacheDao) RemoveSession(ctx context.Context, sessionId string) {
	db.rdb.Del(ctx, _CACHE_PREFIX_SESS+sessionId).Result()
}

func (db *_CacheDao) KeepSessionAlive(ctx context.Context, sessionId, userId string) {
	db.rdb.Expire(ctx, _CACHE_PREFIX_SESS+sessionId, 15*time.Minute).Result()
	db.rdb.Expire(ctx, CACHE_PREFIX_USER_ONLINE+userId, 15*time.Minute).Result()
}

func (db *_CacheDao) SetAdminSession(ctx context.Context, dbItem *AdminSessionDbItem) error {
	data, err := json.Marshal(dbItem)
	if err != nil {
		return err
	}
	return db.rdb.SetEx(ctx, _CACHE_PREFIX_ADMIN_SESS+dbItem.AdminSessionId, data, 3*time.Minute).Err()
}

func (db *_CacheDao) GetAdminSession(ctx context.Context, adminSessionId string) (*AdminSessionDbItem, bool) {
	data, err := db.rdb.Get(ctx, _CACHE_PREFIX_ADMIN_SESS+adminSessionId).Result()
	if err != nil {
		return nil, false
	}
	retItem := &AdminSessionDbItem{}
	err = json.Unmarshal([]byte(data), retItem)
	if err != nil {
		return nil, false
	}
	return retItem, true
}

func (db *_CacheDao) KeepAdminSessionAlive(ctx context.Context, adminSessionId string) {
	_, ok := db.GetAdminSession(ctx, adminSessionId)
	if ok {
		db.rdb.Expire(ctx, _CACHE_PREFIX_ADMIN_SESS+adminSessionId, 3*time.Minute).Result()
	}
}
